/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package atps;


import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

/**
 *
 * @author afonso.rodrigues
 */
public class DateUtils{
    public static final String FORMATO_DATA_DEFAULT = "dd/MM/yyyy";
    public static final String FORMATO_HORA_DEFAULT = "HH:mm";

    public static String getNomeMes(int mes) {
        Date data = getData(1, mes, 1970);
        SimpleDateFormat format = new SimpleDateFormat("MMMM");
        String nomeMes = format.format(data);
        return nomeMes;
    }

    public static String getStringFromHora(Date data) {
        return getStringFromDate(data, FORMATO_HORA_DEFAULT);
    }

    public static String getStringFromDate(Date data) {
        return getStringFromDate(data, FORMATO_DATA_DEFAULT);
    }

    public static String getStringFromDate(Date data, String formato) {
        if (data == null)
            return null;
        SimpleDateFormat format = new SimpleDateFormat(formato);
        String strData = format.format(data);
        return strData;
    }

    public static Date getDateFromString(String strData, String formato) throws ParseException {
        SimpleDateFormat format = new SimpleDateFormat(formato);
        Date data = format.parse(strData);
        return data;
    }

    public static Date getDataHoraAtual() {
        return new Date();
    }

    public static Date getDataHoje() {
        Date dataAtual = new Date();
        Calendar calendar = new GregorianCalendar();
        calendar.setTime(dataAtual);
        calendar.set(GregorianCalendar.HOUR_OF_DAY, 0);
        calendar.set(GregorianCalendar.MINUTE, 0);
        calendar.set(GregorianCalendar.SECOND, 0);
        calendar.set(GregorianCalendar.MILLISECOND, 0);
        return calendar.getTime();
    }

    public static Date getData(int dia, int mes, int ano) {
        Calendar calendar = new GregorianCalendar();
        calendar.set(GregorianCalendar.DAY_OF_MONTH, dia);
        calendar.set(GregorianCalendar.MONTH, mes - 1); // o mês começa em zero no Calendar
        calendar.set(GregorianCalendar.YEAR, ano);
        calendar.set(GregorianCalendar.HOUR_OF_DAY, 0);
        calendar.set(GregorianCalendar.MINUTE, 0);
        calendar.set(GregorianCalendar.SECOND, 0);
        calendar.set(GregorianCalendar.MILLISECOND, 0);
        return calendar.getTime();
    }

    public static Date getTime(int horas, int minutos, int segundos) {
        Calendar calendar = new GregorianCalendar();
        calendar.set(GregorianCalendar.DAY_OF_MONTH, 1);
        calendar.set(GregorianCalendar.MONTH, 0); // o mês começa em zero no Calendar
        calendar.set(GregorianCalendar.YEAR, 0);
        calendar.set(GregorianCalendar.HOUR_OF_DAY, horas);
        calendar.set(GregorianCalendar.MINUTE, minutos);
        calendar.set(GregorianCalendar.SECOND, segundos);
        calendar.set(GregorianCalendar.MILLISECOND, 0);
        return calendar.getTime();
    }

    public static Date getDataHora(int dia, int mes, int ano, int horas, int minutos, int segundos) {
        Calendar calendar = new GregorianCalendar();
        calendar.set(GregorianCalendar.DAY_OF_MONTH, dia);
        calendar.set(GregorianCalendar.MONTH, mes - 1); // o mês começa em zero no Calendar
        calendar.set(GregorianCalendar.YEAR, ano);
        calendar.set(GregorianCalendar.HOUR_OF_DAY, horas);
        calendar.set(GregorianCalendar.MINUTE, minutos);
        calendar.set(GregorianCalendar.SECOND, segundos);
        calendar.set(GregorianCalendar.MILLISECOND, 0);
        return calendar.getTime();
    }

    public static Date getPrimeiroDiaMes(int mes, int ano) {
        return getPrimeiroDiaMes(getData(1, mes, ano));
    }

    public static Date getPrimeiroDiaMes(Date data) {
        int mes = getMes(data);
        int ano = getAno(data);
        return getData(1, mes, ano);
    }

    public static Date getUltimoDiaDoMes(int mes, int ano) {
        return getUltimoDiaDoMes(getData(1, mes, ano));
    }

    public static Date getUltimoDiaDoMes(Date data) {
        int mes = getMes(data);
        int ano = getAno(data);
        GregorianCalendar cal = new GregorianCalendar(ano, mes-1, 1);
        cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH));
        int ultimoDia = cal.get(Calendar.DAY_OF_MONTH);
        return getData(ultimoDia, mes, ano);
    }

    public static Intervalo getIntervaloMes(int mes, int ano) {
        return new Intervalo(getPrimeiroDiaMes(mes, ano), getUltimoDiaDoMes(mes, ano));
    }

    /**
     * Busca o número de milissegundos de uma data.
     * @param data Data cujos milis serão lidos.
     * @return Milissegundos da data.
     */
    public static long getMilisAtStartOfDay(Date data) {
        int hora = getCampo(data, Calendar.HOUR_OF_DAY);
        int minuto = getCampo(data, Calendar.MINUTE);
        int segundo = getCampo(data, Calendar.SECOND);
        int milis = getCampo(data, Calendar.MILLISECOND);
        int totalMilis = (hora * 3600 + minuto * 60 + segundo) * 1000 + milis;
        return totalMilis;
    }
    
    /**
     * Busca o dia do mês em uma data.
     * @param data Data cujo dia do mês será lido.
     * @return Dia do mês da data.
     */
    public static int getDia(Date data) {
        return getCampo(data, Calendar.DAY_OF_MONTH);
    }

    /**
     * Busca o dia da semana em uma data.
     * @param data Data cujo dia da semana será lido.
     * @return Dia da semana da data.
     */
    public static int getDiaDaSemana(Date data) {
        return getCampo(data, Calendar.DAY_OF_WEEK);
    }

    /**
     * Busca o mês em uma data.
     * @param data Data cujo mês será lido.
     * @return Mês da data.
     */
    public static int getMes(Date data) {
        // O campo mês em Calendar inicia em zero, mas precisa iniciar em 1.
        return getCampo(data, Calendar.MONTH) + 1;
    }

    /**
     * Busca o ano em uma data.
     * @param data Data cujo ano será lido.
     * @return Ano da data.
     */
    public static int getAno(Date data) {
        return getCampo(data, Calendar.YEAR);
    }

    /**
     * Busca o valor de um campo da data (dia, mês, ano, hora, minuto, segundo, etc)
     * @param data Data cujo campo será lido.
     * @param campo Identificador do campo conforme constantes da classe java.util.Calendar.
     * @return Valor do campo.
     * @see java.util.Calendar
     */
    private static int getCampo(Date data, int campo) {
        Calendar calendar = new GregorianCalendar();
        calendar.setTime(data);
        return calendar.get(campo);
    }

    public static long getIntervaloDias(Date dataInicial, Date dataFinal) throws Exception {
        GregorianCalendar c1 = new GregorianCalendar();
        c1.setTime(dataInicial);

        GregorianCalendar c2 = new GregorianCalendar();
        c2.setTime(dataFinal);
        long dias = ((c2.getTime().getTime() - c1.getTime().getTime()) / 1000 / 60 / 60 / 24);
        System.out.println("DateUtils.getIntervaloDias - " 
                           + getStringFromDate(dataFinal, "dd/MM/yyyy HH:mm:ss,SSS") 
                           + " - " + getStringFromDate(dataInicial, "dd/MM/yyyy HH:mm:ss,SSS") + " = " + dias);
        return dias;
    }

    public static Date subtraiDia(Date data, int dias) {
        return somaDia(data, dias * -1);
    }

    public static Date somaDia(Date data, int dias) {
        long time = data.getTime();

        // Calcula o tempo a ser somado em milisegundos: dias x 24hs * 60min * 60seg * 1000miliSeg
        long diasMili1 = dias * 24;
        long diasMili2 = diasMili1 * 60;
        long diasMili3 = diasMili2 * 60;
        long diasMili4 = diasMili3 * 1000;

        long novoTempo = time + diasMili4;
        return new Date(novoTempo);
    }

    public static Date somaMes(Date data, int meses) {
        // Obs.: o mês começa em zero no Calendar
        Calendar calendar = new GregorianCalendar();
        calendar.setTime(data);
        int dia = calendar.get(GregorianCalendar.DAY_OF_MONTH);
        int mes = calendar.get(GregorianCalendar.MONTH) + 1;
        int ano = calendar.get(GregorianCalendar.YEAR);
        
        if (mes + meses < 12)
            mes += meses;
        else {
            mes = meses - (12 - mes);
            ano ++;
        }
        
        return getData(dia, mes, ano);    
    }

    public static Date subtraiMes(Date data, int meses) {
        // Obs.: o mês começa em zero no Calendar
        Calendar calendar = new GregorianCalendar();
        calendar.setTime(data);
        int dia = calendar.get(GregorianCalendar.DAY_OF_MONTH);
        int mes = calendar.get(GregorianCalendar.MONTH) + 1;
        int ano = calendar.get(GregorianCalendar.YEAR);
        
        if (mes >= meses)
            mes -= meses;
        else {
            mes = 12 - (meses - mes);
            ano--;
        }
        
        return getData(dia, mes, ano);
    }

    public static Date somaAno(Date data, int anos) {
        // Obs.: o mês começa em zero no Calendar
        Calendar calendar = new GregorianCalendar();
        calendar.setTime(data);
        int dia = calendar.get(GregorianCalendar.DAY_OF_MONTH);
        int mes = calendar.get(GregorianCalendar.MONTH) + 1;
        int ano = calendar.get(GregorianCalendar.YEAR);
        ano += anos;
        return getData(dia, mes, ano);    
    }
    
    public static Date somaSegundos(Date data, int segundos) {
        long time = data.getTime();
        long segMili = segundos * 1000;
        long novoTempo = time + segMili;
        return new Date(novoTempo);
    }

    public static Date somaMinutos(Date data, int minutos) {
        if (data == null)
            data = new Date(0);
        long time = data.getTime();
        long minMili = minutos * 60 * 1000;
        long novoTempo = time + minMili;
        return new Date(novoTempo);
    }

    public static boolean isMesmoDia(Date data1, Date data2) {
        if (getCampo(data1, Calendar.YEAR) != getCampo(data2, Calendar.YEAR))
            return false;
        if (getCampo(data1, Calendar.MONTH) != getCampo(data2, Calendar.MONTH))
            return false;
        if (getCampo(data1, Calendar.DAY_OF_MONTH) != getCampo(data2, Calendar.DAY_OF_MONTH))
            return false;
        return true;
    }

    /** Verifica se a data 1 é maior ou igual à data 2. */
    public static boolean isMaiorOuIgual(Date data1, Date data2) {
        Calendar dt1 = Calendar.getInstance();
        Calendar dt2 = Calendar.getInstance();
        dt1.setTime(data1);
        dt2.setTime(data2);
        if (dt1.after(dt2) || dt1.equals(dt2))
            return true;
        return false;
    }

    /** Verifica se a data 1 é anterior à data 2. */
    public static boolean isAnterior(Date data1, Date data2) {
        Calendar dt1 = Calendar.getInstance();
        Calendar dt2 = Calendar.getInstance();
        dt1.setTime(data1);
        dt2.setTime(data2);
        if (dt1.before(dt2))
            return true;
        return false;
    }

    /** Verifica se a data 1 é posterior à data 2. */
    public static boolean isPosterior(Date data1, Date data2) {
        Calendar dt1 = Calendar.getInstance();
        Calendar dt2 = Calendar.getInstance();
        dt1.setTime(data1);
        dt2.setTime(data2);
        if (dt1.after(dt2))
            return true;
        return false;
    }
    
    public static boolean isNoIntervalo(Date data, Date min, Date max) {
        if (data == null)
            return false;
        
        if (min == null)
            min = new Date(0);
        
        Calendar dt = Calendar.getInstance();
        Calendar dtMin = Calendar.getInstance();
        Calendar dtMax = Calendar.getInstance();
        dt.setTime(data);
        dtMin.setTime(min);
        if (max == null) {
            return !dt.before(dtMin);
        } else {
            dtMax.setTime(max);
            if (dt.before(dtMin) || dt.after(dtMax))
                return false;
        }
        return true;
    }

    public static String getHoraToString(Integer tempo) {
        int horas = tempo / 60;
        int minutos = tempo % 60;

        String strHoras;
        if (horas < 10)
            strHoras = "0" + horas;
        else
            strHoras = "" + horas;

        String strMinutos;
        if (minutos < 10)
            strMinutos = "0" + minutos;
        else
            strMinutos = "" + minutos;

        String strTempo = strHoras + ":" + strMinutos;
        return strTempo;
    }

    public static Date getDataComUltimoDiaDoMes(int mesBaseadoEmZero, int ano) {
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.MONTH, mesBaseadoEmZero);

        return getData(calendar.getActualMaximum(Calendar.DATE), mesBaseadoEmZero + 1, ano);
    }

    /** Transforma o valor de tempo dado milissegundos para o formato HH:MM:SS,SSS */
    public static String getTempoFormatado(long tempo) {
        long milis = tempo;
        long segundos = milis / 1000;
        milis %= 1000;
        long minutos = segundos / 60;
        segundos %= 60;
        long horas = minutos % 60;
        minutos %= 60;
        return String.format("%02d:%02d:%02d,%03d", horas, minutos, segundos, milis);
    }
    
    public static void testMain() throws Exception {
        Date data = getData(6, 2, 2009);
        Date data2 = getData(6, 0, 2009);

        System.out.println("Data 1 é maior que data 2?" + isMaiorOuIgual(data, data2));
        System.out.println("Dias " + DateUtils.getIntervaloDias(data, data2));
        System.out.println("Ultimo dia do mes " + DateUtils.getUltimoDiaDoMes(data));
        System.out.println("Dia 27-28 " + DateUtils.getIntervaloDias(DateUtils.getDateFromString("28/05/2010", "dd/MM/yyyy"), DateUtils.getDateFromString("27/05/2010", "dd/MM/yyyy")));
        System.out.println("Dia 28-28 " + DateUtils.getIntervaloDias(DateUtils.getDateFromString("28/05/2010", "dd/MM/yyyy"), DateUtils.getDateFromString("28/05/2010", "dd/MM/yyyy")));
        System.out.println("Dia 29-28 " + DateUtils.getIntervaloDias(DateUtils.getDateFromString("28/05/2010", "dd/MM/yyyy"), DateUtils.getDateFromString("29/05/2010", "dd/MM/yyyy")));
        System.out.println("Dia 30-28 " + DateUtils.getIntervaloDias(DateUtils.getDateFromString("28/05/2010", "dd/MM/yyyy"), DateUtils.getDateFromString("30/05/2010", "dd/MM/yyyy")));
        System.out.println("Dia 10-28 " + DateUtils.getIntervaloDias(DateUtils.getDateFromString("28/05/2010", "dd/MM/yyyy"), DateUtils.getDateFromString("10/06/2010", "dd/MM/yyyy")));

        testaSomaDias("29/07/2010", 25);
        testaSomaDias("01/12/2009", 30);
        testaSomaDias("05/02/2010", 41);
        
        testaSubtraiMes();
        
        System.out.println("2:35:45 horas = " + getMilisAtStartOfDay(getDateFromString("2:35:45", "HH:mm:ss")) + " segundos");
        System.out.println("dia da semana = " + getDiaDaSemana(getDateFromString("20/12/2011", "dd/MM/yyyy")));
        System.out.println("dia da semana = " + getDiaDaSemana(getDateFromString("19/12/2011", "dd/MM/yyyy")));
        System.out.println("dia da semana = " + getDiaDaSemana(getDateFromString("18/12/2011", "dd/MM/yyyy")));
        System.out.println("dia da semana = " + getDiaDaSemana(getDataHoje()));
        System.out.println(getData(1,1,2011));
    }

    private static void testaSomaDias(String strData, int dias) throws ParseException {
        Date data = DateUtils.getDateFromString(strData, "dd/MM/yyyy");
        Date novaData = DateUtils.somaDia(data, dias);
        System.out.println(DateUtils.getStringFromDate(data) + " " + dias + " dias = " + DateUtils.getStringFromDate(novaData));
    }
    
    private static void testaSubtraiMes() {
        Date d1 = getData(1, 4, 2010);
        Date d1_1 = subtraiMes(d1, 1);
        Date d1_2 = subtraiMes(d1, 4);
        Date d1_3 = subtraiMes(d1, 10);
        System.out.println(getStringFromDate(d1, "dd/MM/yyyy") + " - 1 = " + getStringFromDate(d1_1, "dd/MM/yyyy"));
        System.out.println(getStringFromDate(d1, "dd/MM/yyyy") + " - 4 = " + getStringFromDate(d1_2, "dd/MM/yyyy"));
        System.out.println(getStringFromDate(d1, "dd/MM/yyyy") + " - 10 = " + getStringFromDate(d1_3, "dd/MM/yyyy"));
    }
    
    public static class Intervalo {
        private Date dataInicial;
        private Date dataFinal;

        public Intervalo() {
            super();
        }
        
        public Intervalo(Date dataInicial, Date dataFinal) {
            this.dataInicial = dataInicial;
            this.dataFinal = dataFinal;
        }
        
        public int getAnos() {
            int anos = 0;
            if (isPosterior(dataFinal, dataInicial)) {
                int anoInicial = getAno(dataInicial);
                int mesInicial = getMes(dataInicial);
                int anoFinal = getAno(dataFinal);
                int mesFinal = getMes(dataFinal);
                anos = anoFinal - anoInicial;
                if (mesFinal < mesInicial)
                    anos--;
            }
            return anos;
        }
        
        public void setDataInicial(Date dataInicial) {
            this.dataInicial = dataInicial;
        }

        public Date getDataInicial() {
            return dataInicial;
        }

        public void setDataFinal(Date dataFinal) {
            this.dataFinal = dataFinal;
        }

        public Date getDataFinal() {
            return dataFinal;
        }
    }
    
}